<template>
  <div class="img-upload-container">
    <el-upload
      v-model:file-list="fileList"
      action=""
      :limit="setting.limit"
      accept=".jpg,.jpeg,.png,.gif"
      list-type="picture-card"
      :on-exceed="handleExceed"
      :on-error="handleError"
      :before-upload="beforeUpload"
      :on-preview="handlePreview"
      :http-request="handleHttpRequest"
      :disabled="props.disabled"
    >
      <el-icon><Plus /></el-icon>
    </el-upload>

    <!-- 图片预览对话框 -->
    <el-dialog v-model="previewVisible" :key="previewUrl">
      <img w-full :src="previewUrl" alt="Preview Image" />
    </el-dialog>

    <div class="upload-tip">
      <p>支持上传的图片格式：jpgjpeg|png|gif</p>
      <p>图片大小限制：{{ setting.imgSize }}MB以内</p>
      <p v-if="setting.limit > 1">最多可上传 {{ setting.limit }} 张图片</p>
    </div>
  </div>
</template>

<script setup>
import { computed, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'
import { singleUpload } from '@/utils/upload'

const props = defineProps({
  modelValue: {
    type: Array,
    default: () => []
  },
  setting: {
    type: Object,
    default: () => {}
  },
  formRules: {
    type: Object,
    default: () => ({})
  },
  disabled: {
    type: Boolean,
    default: false
  }
})

const emits = defineEmits(['update:modelValue', 'update:formRules'])
const singleActionUrl = ref(process.env.VUE_APP_SERVICE_BASE + '/file/sysFile/upload')
const fileList = computed({
  get: () => {
    return (props.modelValue || []).map(item => ({
      name: item.fileName,
      url: item.url
    }))
  },
  set: (val) => {
    if (!val) return
    if (JSON.stringify(val) === JSON.stringify(fileList.value)) {
      return
    }
    const newVal = val.map(item => ({
      fileName: item.name,
      url: item.url
    }))
    emits('update:modelValue', newVal)
  }
})
const previewVisible = ref(false)
const previewUrl = ref('')

// 处理 formRules
const formRules = computed({
  get: () => props.formRules,
  set: (val) => {
    emits('update:formRules', val)
  }
})

// 处理超出文件数量限制
const handleExceed = () => {
  ElMessage.warning(`最多只能上传 ${props.setting.limit} 张图片`)
}

// 上传前验证
const beforeUpload = (file) => {
  // 验证文件大小
  const isLtSize = file.size / 1024 / 1024 < props.setting.imgSize
  if (!isLtSize) {
    ElMessage.error(`图片大小不能超过 ${props.setting.imgSize}MB!`)
    return false
  }

  // 验证文件类型
  const fileName = file.name
  const fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase()
  const isValidType = ['jpg', 'jpeg', 'png', 'gif'].includes(fileExt)
  
  if (!isValidType) {
    ElMessage.error('图片格式不正确!')
    return false
  }
  
  return true
}

// 处理图片预览
const handlePreview = (uploadFile) => {
  previewUrl.value = uploadFile.url
  previewVisible.value = true
}

// 上传成功处理
const handleHttpRequest = async (option) => {
  let data = new FormData()
  data.append('file', option.file)
  // 获取图片文件的宽高属性
  const { width, height, scale } = await getImageSize(option.file, 2000)
  data.append('cropWidth', width)
  data.append('cropHeight', height)
  data.append('scaledWidth', width)
  data.append('scaledHeight', height)
  data.append('startX', 0)
  data.append('startY', 0)
  data.append('path', 'content')
  data.append('type', 0)
  if (scale < 1) {
    data.append('canMini', true)
  }
  try {
    let res = await singleUpload(data, singleActionUrl.value, option.onProgress)
    handleSuccess(res.data.url)
  } catch (error) {
    handleError(option.file.uid)
  }
}

// 上传成功处理
const handleSuccess = (url) => {
  fileList.value[fileList.value.length - 1].url = url
  emits('update:modelValue', fileList.value.map(item => ({
    fileName: item.name,
    url: item.url
  })))
}

// 上传失败处理
const handleError = (uid) => {
  ElMessage.error('上传失败')
  const index = fileList.value.findIndex(file => file.uid === uid)
  fileList.value.splice(index, 1)
}

// 生成校验规则
const generateRules = () => {
  const rules = []

  if (props.setting.require) {
    rules.push({
      required: true,
      message: '此题为必填题',
      trigger: 'change',
      validator: (rule, value, callback) => {
        if (!fileList.value || fileList.value.length === 0) {
          callback(new Error('请上传图片'))
          return
        }
        callback()
      }
    })
  }

  formRules.value[props.setting.formItemId] = rules
}

// 根据图片file获取图片宽高属性
const getImageSize = (file, maxWidth) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = (e) => {
      const img = new Image()
      img.onload = () => {
        let scale = 1
        let width = img.width
        let height = img.height
        // 如果图片宽度大于 maxWidth，进行缩放
        if (width > maxWidth) {
          scale = maxWidth / width
          width = maxWidth
          height = Math.round(height * scale)
        }
        resolve({ width, height, scale })
      }
      img.onerror = (error) => {
        console.error('图片加载失败:', error)
        reject(error)
      }
      img.src = e.target.result
    }
    reader.readAsDataURL(file)
  })
}

// 组件挂载时生成验证规则
onMounted(() => {
  generateRules()
})
</script>

<style lang="scss" scoped>
.img-upload-container {
  width: 100%;

  :deep(.el-upload--picture-card) {
    width: 148px;
    height: 148px;
    line-height: 148px;
  }

  .upload-tip {
    color: #909399;
    font-size: 12px;
    line-height: 1.5;
    margin-top: 8px;
  }
}

:deep(.el-dialog__body) {
  text-align: center;

  img {
    max-width: 100%;
    max-height: 70vh;
  }
}
</style>
